/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Model;
import java.io.*;
import java.lang.System.*;
import java.util.*;

/**
 *
 * @author snowangelic
 */
public class Main {

    /**
     * @param args the command line arguments
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        DataSet set=new DataSet();
        int exit=0;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        System.out.println("");
        System.out.println("Welcome to Kmeans !");
        System.out.println("Kmeans is a clustering software realized for learning purposes");
        System.out.println("it should not be used in a production environment...");
        System.out.println("The Kmeans dev team - ULB Polytechnique.");
        System.out.println("");
        System.out.println("Please type Help to view available commands");
        while(exit!=1){
            System.out.println("");
            System.out.print("Kmeans> ");
            String command=br.readLine();
            String[] commandArgs=command.split(" ");

            //--- Exit ---
            if(commandArgs[0].equals("Exit")){
                exit=1;
            }


            //--- Help ---
            else if(commandArgs[0].equals("Help")){
                System.out.println("Available commands :");
                System.out.println("--------------------");
                System.out.println(" ");
                System.out.println("> Exit");
                System.out.println("Closes the program");
                System.out.println(" ");
                System.out.println("> Add attribute [Name] [Type]");
                System.out.println("Creates a new attribute named [Name] of type [Type]");
                System.out.println("available type are : Numerical - String");
                System.out.println("eg : > Add attribute Price Numerical");
                System.out.println(" ");
                System.out.println("> Add action [attr1] [attr2] ... [attrN]");
                System.out.println("Creates a new action with the specified attributes");
                System.out.println("the attributes entered must correspond to their types");
                System.out.println("and be entered in the same order the attributes where entered");
                System.out.println("eg : > Add action Jean 75 1.80");
                System.out.println("first attribute is of type String, second and third are of type");
                System.out.println("Numerical");
                System.out.println(" ");
                System.out.println("> View");
                System.out.println("Shows the Data Set and the clustering result in a nice spreadsheet-like");
                System.out.println("view");
                System.out.println(" ");
                System.out.println("> Clusterize");
                System.out.println("Will clusterize the data with the Kmeans Algorithm. You will be prompted");
                System.out.println("for the numbre of clusters, thier names and thier color. You will also");
                System.out.println("be asked the relative weight of each attribute. For now, please enter 0");
                System.out.println("for String attributes");
                System.out.println(" ");
                System.out.println("> QuickData");
                System.out.println("Creates a Data Set of 16 actions caracterized by 4 attributes (2 String");
                System.out.println("and 2 Numerical. this function is used to allow quick tests without having");
                System.out.println("to enter attributes and action manually");
                System.out.println(" ");
                System.out.println("> Test3D");
                System.out.println("Add random coordinates to the actions already created and launch the");
                System.out.println("3d viewer. It is recommended to generate data with Quickdata before");
                System.out.println("starting this test. Data must be clusterized. Use left click to rotate,");
                System.out.println("right click to translate, Atl+left click to zoom");
            }

            //--- QuickData ---
            else if(commandArgs[0].equals("QuickData")){
                set.addAttribute("Nom",AttributeType.TextualDiscreet);
                set.addAttribute("Type",AttributeType.TextualDiscreet);
                set.addAttribute("Poids",AttributeType.Numerical);
                set.addAttribute("Taille",AttributeType.Numerical);

                ArrayList<AttributeValue> attributeList=new ArrayList<AttributeValue>();
                AttributeValue attribut;

                attribut=new AttributeValue(set.getAttribute(0),"Jean");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Grand Maigre");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 50);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 2.05);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"Pierre");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Grand Maigre");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 65);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 2.05);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"Marc");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Grand Maigre");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 60);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 2);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"Xavier");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Grand Gros");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 95);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 2);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"Bertrand");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Grand Gros");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 105);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 2);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"Nicolas");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Grand Maigre");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 50);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 1.95);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"Michel");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Grand Maigre");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 65);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 1.9);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"Laurent");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Grand Gros");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 95);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 1.9);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"Theo");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Grand Gros");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 105);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 1.9);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"Barnabe");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Petit Maigre");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 50);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 1.7);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"Balthazar");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Petit Maigre");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 60);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 1.65);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"Brandon");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Petit Maigre");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 70);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 1.65);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"Kevin");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Petit Gros");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 100);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 1.65);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"Christian");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Petit Gros");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 110);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 1.65);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"George");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Petit Maigre");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 50);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 1.6);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"Jacques");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Petit Gros");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 100);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 1.6);
                attributeList.add(attribut);
                set.addAction(attributeList);

                attributeList=new ArrayList<AttributeValue>();
                attribut=new AttributeValue(set.getAttribute(0),"Florent");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(1),"Petit Maigre");
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(2),(float) 60);
                attributeList.add(attribut);
                attribut=new AttributeValue(set.getAttribute(3),(float) 1.55);
                attributeList.add(attribut);
                set.addAction(attributeList);

                System.out.println("Data created");

            }
//
//
//            //--- Add ---
//            else if(commandArgs[0].equals("Add")){
//                //--- Add Attribute ---
//                if(commandArgs[1].equals("attribute")){
//                    set.addAttribute(commandArgs[2], commandArgs[3]);
//                    System.out.println("Attribute Added");
//                }
//
//                //--- Add Action ---
//                if(commandArgs[1].equals("action")){
//                    ArrayList<AttributeValue> attributeList=new ArrayList<AttributeValue>();
//                    for(int i=2;i<commandArgs.length;i++){
//                        if(set.getAttributeType(i-2).equals("Numerical")){
//                           float nbr = Float.parseFloat(commandArgs[i]);
//                           AttributeValue attr=new NumericalValue(set.getAttribute(i-2),nbr);
//                           attributeList.add(attr);
//                        }
//                        else if(set.getAttributeType(i-2).equals("String")){
//                           AttributeValue attr=new StringValue(set.getAttribute(i-2),commandArgs[i]);
//                           attributeList.add(attr);
//                        }
//                        else{
//                            System.out.println("Problem with Attribute Type");
//                        }
//                    }
//                    set.addAction(attributeList);
//                    System.out.println("Action Added");
//                }
//
//            }
            // --- Visualilser le dataset ---
            else if(commandArgs[0].equals("View")){
                    String[][] stringArray=new String[set.getActionNbr()+1][1+set.getAttributeNbr()+set.getKmeansNbr()];
                    stringArray[0][0]="";
                    for(int i=0;i<set.getAttributeNbr();i++){
                        stringArray[0][i+1]=set.getAttributeName(i);
                    }
                    for(int i=0;i<set.getKmeansNbr();i++){
                        stringArray[0][1+set.getAttributeNbr()+i]=set.getKmeansName(i);
                    }

                    for(int i=0;i<set.getActionNbr();i++){
                        stringArray[i+1][0]=""+i;
                        for(int j=0;j<set.getAttributeNbr();j++){
                            stringArray[i+1][j+1]=set.getValue(i, j).toString();
                        }
                        for(int j=0;j<set.getKmeansNbr();j++){
                            stringArray[i+1][1+set.getAttributeNbr()+j]=set.getClusterName(i,set.getKmeans(j));
                        }
                    }
                    printStringArray(stringArray);
            }

            // --- Clusteriser les données---
            else if(commandArgs[0].equals("Clusterize")){
                System.out.print("Name : ");
                String name=br.readLine();

                String distance="Euclidian";
                Kmeans newKmeans=set.addKmeans(name,distance);

                System.out.print("Cluster number  : ");
                int clusterNbr=Integer.parseInt(br.readLine());

                for(int i=0;i<clusterNbr;i++){
                    System.out.print("\n");
                    System.out.println("Cluster "+i);
                    System.out.print("Name : ");
                    String clusName=br.readLine();
                    System.out.print("Color (Red,Blue,Yellow,Green,Magenta) : ");
                    String clusColor=br.readLine();
                    set.addCluster(newKmeans,clusName,clusColor);
                }

                for(int i=0;i<set.getAttributeNbr();i++){
                    System.out.print("\n");
                    System.out.println("Relative weight for attribute : "+set.getAttributeName(i));

                    float weightVal=Float.parseFloat(br.readLine());
                    if(weightVal!=0){
                        set.addWeight(newKmeans,i,weightVal);
                    }

                }

                System.out.print("Compute Kmeans ? (y/n) default y : ");
                String strCompute=br.readLine();
                boolean compute=true;
                if(strCompute.equals("n")) compute=false;

                if(compute==true) set.computeKmeans(newKmeans);
            }

            // --- Tester l'affichage 3D ---
            else if(commandArgs[0].equals("Test3D")){
                System.out.print("Number of the clusterization : ");
                int kmeansNumber=Integer.parseInt(br.readLine());

                /*
                 * Rajoute des coordonnées random à toutes les actions déjà créées
                 */
                int n = set.getActionNbr();
                Random rand = new Random();
                float[] coords;
                for (int i=0;i<n;i++){
                    coords = new float[]{rand.nextFloat()*2-1,
                                         rand.nextFloat()*2-1,
                                         rand.nextFloat()*2-1};
                    set.getAction(i).setCoords(coords);
                }

                new View3D(set,set.getKmeans(kmeansNumber)).setVisible(true);
            }

            // --- Sinon... ---
            else{
                System.out.println("Unknown command");
            }


        }
        System.exit(0);
    }

    private static int maxLength(String[][] stringArray,int colIndex) {
        int maxLength=0;
        for(int i=0;i<stringArray.length;i++){
            if(stringArray[i][colIndex].length()>maxLength) maxLength=stringArray[i][colIndex].length();
        }
        return maxLength;
    }

    private static void printSeparator(int[] maxLength) {
        for(int i=0;i<maxLength.length;i++){
            System.out.print("+");
            for(int j=0;j<maxLength[i];j++){
                System.out.print("-");
            }
        }
        System.out.print("+");
        System.out.print("\n");
    }


    private static void printStringArray(String[][] stringArray){
        System.out.print("\n");
        int[] maxLength = new int[stringArray[0].length];
        for(int i=0;i<stringArray[0].length;i++){
            maxLength[i]=maxLength(stringArray,i);
            for(int j=0;j<stringArray.length;j++){
                while(stringArray[j][i].length()<maxLength[i]){
                    stringArray[j][i]=stringArray[j][i].concat(" ");
                }
            }
        }
        for(int i=0;i<stringArray.length;i++){
            printSeparator(maxLength);
            System.out.print("|");
            for(int j=0;j<stringArray[0].length;j++){
                System.out.print(stringArray[i][j]);
                System.out.print("|");
            }
            System.out.print("\n");
        }
        printSeparator(maxLength);
    }
}
